home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / bin / pymou < prev    next >
Encoding:
Text File  |  2006-12-14  |  17.1 KB  |  462 lines

  1. #!/usr/bin/python
  2. # Class for finding out what partitions are available to us to mount, via /proc/partitions, /etc/mtab and /etc/fstab
  3. # NOTE: Only works for devices that are 3 char block devices in /dev/ and udev systems.
  4.  
  5. import gtk
  6. import gtk.glade
  7. import os
  8. import sys
  9. import popen2
  10.  
  11. # Line the /proc/partition starts showing drive data
  12. STARTLINE = 2
  13. # Length of "/dev/" in chars
  14. DEVLEN = 5
  15. # Bytes in a block
  16. BLOCKSIZE=1024
  17. AMILLION = 1000000
  18. # Device prefix
  19. DEV="/dev/"
  20. # fstab line 'users', means the device is mountable/unmountable by all users
  21. USERS_MOUNTABLE="users"
  22. USER_MOUNTABLE="user"
  23.  
  24. # Get our effective user ID so we know if we can mount/unmount certain partitions
  25. UID=os.geteuid()
  26. ROOT=0
  27.  
  28. if not os.path.exists("pymou.glade"):
  29.     DATA_DIR="/usr/share/pymou/"
  30. else:
  31.     print "Using relative directory structure"
  32.     DATA_DIR=""
  33.                 
  34.  
  35. # Partition object, contains information about the partition
  36. class Partition:
  37.     def __init__(self, procline):
  38.         partdata = procline.split()
  39.         self.major = partdata[0]
  40.         self.minor = partdata[1]
  41.         self.blocks = partdata[2]
  42.         self.name = partdata[3]
  43.         self.disk = partdata[3][:3]
  44.         self.size = int(self.blocks) * BLOCKSIZE / AMILLION 
  45.         if not self.name == self.disk:
  46.             self.parent = False
  47.             self.partNum = partdata[3][3:]
  48.             if int(self.partNum) <= 4:
  49.                 self.primary = True
  50.                 self.logical = False
  51.             else:
  52.                 self.primary = False
  53.                 self.logical = True
  54.         else:
  55.             self.parent = True
  56.         self.mounted = False
  57.         self.mountpoint = ""
  58.         self.fstabIndex = -1
  59.         self.fs = "unknown"
  60.         self.users = self.user = False # Is the partition mountable by anyone?
  61.  
  62.     def toString(self):
  63.         return "%s %s %s %s %s" % (self.major, self.minor, self.blocks, self.name, self.disk)
  64.  
  65. # Reads partition information from mtab, fstab and /proc/partitions and generates Partition objects
  66. class PartInfo:
  67.     def __init__(self):
  68.         self.partitions = {}
  69.         self.partitionTree = {}
  70.         self.fstab = []
  71.  
  72.     def readProcFile(self, procfile):
  73.         partLines = open(procfile).readlines()
  74.         self.buildPartitionDict(partLines)
  75.         self.buildPartitionTree()
  76.  
  77.     def buildPartitionTree(self):
  78.         self.partitionTree = {}
  79.         for partition in self.partitions:
  80.             if not self.partitions[partition].parent:
  81.                 disk = self.partitions[partition].disk
  82.                 try:
  83.                     self.partitionTree[disk].append(partition)
  84.                 except KeyError:
  85.                     self.partitionTree[disk] = []
  86.                     self.partitionTree[disk].append(partition)
  87.         for partition in self.partitionTree:
  88.             self.partitionTree[partition].sort()
  89.  
  90.     def buildPartitionDict(self, partLines):
  91.         for line in partLines[STARTLINE:]:
  92.             #ignore devices that are not sdXY or hdXY.
  93.             split = line.split()
  94.             for x in ["h", "s"]:
  95.                 if split[3][0] == x:
  96.                     partition = Partition(line)
  97.                 if not self.partitions.has_key(partition.name):
  98.                     self.partitions[partition.name] = partition
  99.  
  100.     def printPartitionDict(self):
  101.         for partition in self.partitions:
  102.             print self.partitions[partition].toString()
  103.             
  104.     def printPartitionTree(self):
  105.         for partition in self.partitionTree:
  106.             print partition
  107.             outline = "-"
  108.             for part in self.partitionTree[partition]:
  109.                 outline += " " + part
  110.             print outline
  111.  
  112.     def resetMounted(self):
  113.         for partition in self.partitions:
  114.             self.partitions[partition].mounted = False
  115. #            self.partitions[partition].mountpoint = ""
  116.  
  117.     def readMtab(self, mtabfile):
  118.         self.resetMounted()
  119.         mountLines = open(mtabfile).readlines()
  120.         for line in mountLines:
  121.             split = line.split()
  122.             if split[0].find(DEV) >= 0:
  123.                 device = split[0][DEVLEN:]
  124.                 try:
  125.                     self.partitions[device].mounted = True
  126.                     self.partitions[device].mountpoint = split[1]
  127.                     self.partitions[device].fs = split[2]
  128.                 except KeyError:
  129.                     print "Warning: device %s is mounted, but does not exist" % (device)
  130.  
  131.     def readFstab(self, fstabfile):
  132.         self.fstab = open(fstabfile).readlines()
  133.         for partition in self.partitions:
  134.             self.partitions[partition].fstabIndex = -1
  135.         for x in range(len(self.fstab)):
  136.             line = self.fstab[x] = self.fstab[x].strip()
  137.             if line == "" or line[0] == '#':
  138.                 continue
  139.             split = line.split()
  140.             if split[0].find(DEV) >= 0:
  141.                 device = split[0][DEVLEN:]
  142.                 try:
  143.                     self.partitions[device].fstabIndex = x
  144.                     if line.find(USERS_MOUNTABLE) >= 0:
  145.                         self.partitions[device].users = True
  146.                     else:
  147.                         self.partitions[device].users = False
  148.                     if line.find(USER_MOUNTABLE) >= 0:
  149.                         self.partitions[device].user = True
  150.                     else:
  151.                         self.partitions[device].user = False
  152.                 except KeyError:
  153.                     print "Warning: device %s is in fstab, but does not exist" % (device)
  154.  
  155.     def printMounted(self):
  156.         for partition in self.partitions:
  157.             if self.partitions[partition].mounted:
  158.                 print "%s mounted on %s" % (partition, self.partitions[partition].mountpoint)
  159.  
  160. # Wrapper for gtk.glade.XML, let's objects be called with xml.widget instead of xml.get_widget(widget)
  161. class GladeObj(gtk.glade.XML):
  162.     def __getattr__(self, attr):
  163.         try:
  164.             return self.get_widget(attr)
  165.         except KeyError:
  166.             print "No such widget"
  167.  
  168. # Overrides stdout
  169. class Output:
  170.     def __init__(self, outfunc):
  171.         self.output = outfunc
  172.         
  173.     def write(self, text):
  174.         self.output(text)
  175.  
  176.  
  177. # Wrapper class for mount/unmount commands
  178. class Mounter:
  179.     def __init__(self):
  180.         self.commands = {}
  181.         self.commands['mount'] = "mount"
  182.         self.commands['unmount'] = "umount"
  183.  
  184.     def execCmd(self, cmd):
  185.         pop = popen2.Popen4(cmd)
  186.         ret = pop.wait()
  187.         output = pop.fromchild.read().strip()
  188.         return ret, output
  189.  
  190.     def mount(self, device, location, fs=None):
  191.         device = "%s%s"%(DEV, device)
  192.         args = [device, location]
  193.         command = "%s %s" % (self.commands['mount'], ' '.join(args))
  194.         
  195.         ret, output = self.execCmd(command)
  196.         if not output == "":
  197.             print output
  198.         return ret
  199. #        fd = os.popen3(command, 'r')
  200. #        output = fd[1].read()
  201. #        output += fd[2].read()
  202. #        output.strip()
  203. #        fd = os.popen(command, 'r')
  204. #        output = fd.read()
  205. #        output.strip()
  206. #        print output
  207. #        return 
  208.  
  209.     def unmount(self, location):
  210.         args = [location]
  211.         command = "%s %s" % (self.commands['unmount'], ' '.join(args))
  212.         
  213.         ret, output = self.execCmd(command)
  214.         if not output == "":
  215.             print output
  216.         return ret
  217. #        fd = os.popen3(command, 'r')
  218. #        output = fd[1].read()
  219. #        output += fd[2].read()
  220. #        output.strip()
  221. #
  222. #        print output
  223. #        return
  224.  
  225. class MountGui:
  226.     def __init__(self):
  227.         self.xml = GladeObj(DATA_DIR+"pymou.glade")
  228.         self.outputBuffer = self.xml.outputView.get_buffer()
  229.         # Overwrite stdout and stderr to our output window
  230.         sys.stdout = Output(self.output)
  231.         sys.stderr = Output(self.output)
  232.         
  233.         self.mounter = Mounter()
  234.         self.partInfo = PartInfo()
  235.         self.partInfo.readProcFile("/proc/partitions")
  236.         self.partInfo.readMtab("/etc/mtab")
  237.         self.partInfo.readFstab("/etc/fstab")
  238.         
  239.         self.buildPartStore()
  240.         self.buildPartSelection()
  241.         self.updatePartStore()
  242.         self.updateFstabView()
  243.         self.connectHandlers()
  244.  
  245.     def buildPartStore(self):
  246.         # (icon name, partition name, mountpoint)
  247.         self.partStore = gtk.TreeStore(str, str, str)
  248.         column = gtk.TreeViewColumn()
  249.         cellPB = gtk.CellRendererPixbuf()
  250.         cellStr = gtk.CellRendererText()
  251.         cellMnt = gtk.CellRendererText()
  252.         column.pack_start(cellPB, False)
  253.         column.add_attribute(cellPB, 'stock-id', 0)
  254.         column.pack_start(cellStr, True)
  255.         column.set_attributes(cellStr, text=1)
  256.         column.pack_start(cellMnt, True)
  257.         column.set_attributes(cellMnt, text=2)
  258.         column.set_widget(None)
  259.         self.xml.partView.append_column(column)
  260.         self.xml.partView.set_headers_visible(False)
  261.         self.xml.partView.set_model(self.partStore)
  262.  
  263.     def buildPartSelection(self):
  264.         self.partSelection = self.xml.partView.get_selection()
  265.         self.partSelection.set_select_function(self.part_selected, None)
  266.  
  267.     def updatePartStore(self):
  268.         self.partStore.clear()
  269.         for part in self.partInfo.partitionTree:
  270.             parentIter = self.partStore.append(None, (gtk.STOCK_HARDDISK, part, ""))
  271.             for subpart in self.partInfo.partitionTree[part]:
  272.                 if self.partInfo.partitions[subpart].mounted:
  273.                     if not self.partInfo.partitions[subpart].users and not UID == ROOT:
  274.                         icon = gtk.STOCK_DIALOG_AUTHENTICATION
  275.                     else:
  276.                         icon = gtk.STOCK_YES
  277.                 else:
  278.                     if self.partInfo.partitions[subpart].user or self.partInfo.partitions[subpart].users or UID == ROOT:
  279.                         icon = gtk.STOCK_NO
  280.                     else:
  281.                         icon = gtk.STOCK_DIALOG_AUTHENTICATION
  282.                 self.partStore.append(parentIter, (icon , subpart, self.partInfo.partitions[subpart].mountpoint))
  283.         self.xml.partView.expand_all()
  284.  
  285.     def updateFstabView(self):
  286.         fstabBuffer = self.xml.fstabView.get_buffer()
  287.         fstab = ""
  288.         for line in self.partInfo.fstab:
  289.             fstab += line + '\n'
  290.         fstabBuffer.set_text(fstab)
  291.         self.xml.fstablabel.set_label("<b>Fstab</b>")
  292.         
  293.  
  294.     def connectHandlers(self):
  295.         self.xml.mountbtn.connect('clicked', self.mount)
  296.         self.xml.unmountbtn.connect('clicked', self.unmount)
  297.         self.xml.refreshbtn.connect('clicked', self.refresh)
  298.         self.xml.clearbtn.connect('clicked', self.clear)
  299.         self.xml.mntpointbtn.connect('clicked', self.showFolderChooser)
  300.         self.xml.savefstabbtn.connect('clicked', self.saveFstab)
  301.         self.xml.outputView.connect('expose_event', self.outputUnbold)
  302.         self.xml.fstabView.connect('expose_event', self.fstabUnbold)
  303.         self.xml.folderchooser.connect('response', self.choseMountpoint)
  304.         self.xml.pymou.connect('destroy', self.quit)
  305.  
  306.     def part_selected(self, path, args):
  307.         iter = self.partStore.get_iter(path)
  308.         partition = self.partInfo.partitions[self.partStore.get_value(iter, 1)]
  309.         
  310.         self.xml.majorlabel.set_label(partition.major)
  311.         self.xml.minorlabel.set_label(partition.minor)
  312.         self.xml.blocklabel.set_label(partition.blocks)
  313.         self.xml.sizelabel.set_label(str(partition.size))
  314.         try:
  315.             # Set the labels to what we want and change the mount/unmount button active status.
  316.             if partition.mounted:
  317.                 mounted = "Yes"
  318.                 self.xml.mountbtn.set_property('sensitive', False)
  319.                 self.xml.unmountbtn.set_property('sensitive' ,True)
  320. #                self.xml.clearbtn.set_property('sensitive', False)
  321.             else:
  322.                 self.xml.mountbtn.set_property('sensitive', True)
  323.                 self.xml.unmountbtn.set_property('sensitive' ,False)
  324. #                self.xml.clearbtn.set_property('sensitive', True)
  325.                 mounted = "No"
  326.             if partition.logical == True:
  327.                 type = "Logical"
  328.             else:
  329.                 type = "Primary"
  330.             self.xml.mountedlabel.set_label(mounted)
  331.             self.xml.typelabel.set_label(type)
  332.             self.xml.fslabel.set_label(partition.fs)
  333.             self.xml.mountpointlabel.set_label(partition.mountpoint)
  334.             if partition.fstabIndex >= 0:
  335.                 self.xml.fstabentrylabel.set_label(self.partInfo.fstab[partition.fstabIndex])
  336.             else:
  337.                 self.xml.fstabentrylabel.set_label("")
  338.             self.xml.mntpointbtn.set_property('sensitive', True)
  339.             self.xml.clearbtn.set_property('sensitive', True)
  340.             
  341.         except AttributeError:
  342.             self.xml.mountedlabel.set_label("")
  343.             self.xml.mountpointlabel.set_label("")
  344.             self.xml.fstabentrylabel.set_label("")
  345.             self.xml.typelabel.set_label("")
  346.             self.xml.fslabel.set_label("none")
  347.             self.xml.mntpointbtn.set_property('sensitive', False)
  348.             self.xml.mountbtn.set_property('sensitive', False)
  349.             self.xml.unmountbtn.set_property('sensitive' ,False)
  350.             self.xml.clearbtn.set_property('sensitive', False)
  351.         
  352.         return True
  353.  
  354.     def refresh(self, obj=None):
  355.         print "Rereading Partition Information"
  356.         
  357.         self.partInfo.readProcFile("/proc/partitions")
  358.         self.partInfo.readMtab("/etc/mtab")
  359.         self.partInfo.readFstab("/etc/fstab")
  360.  
  361.         self.updatePartStore()
  362.         self.updateFstabView()
  363.  
  364.     def clear(self, obj):
  365.         model, iter = self.partSelection.get_selected()
  366.         device = model.get_value(iter, 1)
  367.         mountpoint = ""
  368.         print "Clearing mount point for %s" % (device)
  369.         self.partInfo.partitions[device].mountpoint = mountpoint
  370.         model.set_value(iter, 2, mountpoint)
  371.         
  372.  
  373.     def mount(self, obj):
  374.         model, iter = self.partSelection.get_selected()
  375.         device = model.get_value(iter, 1)
  376.         mountpoint = self.partInfo.partitions[device].mountpoint
  377.         fstabIndex = self.partInfo.partitions[device].fstabIndex
  378.         if mountpoint == "" and fstabIndex < 0:
  379.             print "Warning: Mountpoint undefined and no entry in fstab for device %s" % device
  380.             return
  381.         if not mountpoint == "":
  382.             print "mounting %s at %s" % (device, mountpoint)
  383.         else:
  384.             print "mounting %s" % (device)
  385.         if not self.mounter.mount(device, mountpoint) == 0:
  386.             if self.partInfo.partitions[device].fstabIndex >= 0:
  387.                 print "mounting %s at %s failed, trying to mount according to fstab" % (device, mountpoint)
  388.                 if self.mounter.mount(device, "") == 0:
  389.                     print "Successfully mounted %s" % (device)
  390.         else:
  391.             print "Successfully mounted %s" % (device)
  392.             
  393.         self.refresh()
  394.  
  395.     def unmount(self, obj):
  396.         model, iter = self.partSelection.get_selected()
  397.         device = model.get_value(iter, 1)
  398.         if self.partInfo.partitions[device].mounted:
  399.             mountpoint = self.partInfo.partitions[device].mountpoint
  400.             print "unmounting %s from %s" % (device, mountpoint)
  401.             ret = self.mounter.unmount(mountpoint)
  402.             self.refresh()
  403.         else:
  404.             print "Warning: %s is not mounted" % device
  405.         return
  406.         
  407.  
  408.     def output(self, text):
  409.         end_iter = self.outputBuffer.get_end_iter()
  410.         self.outputBuffer.insert(end_iter, text)
  411.         end_mark = self.outputBuffer.create_mark(None, self.outputBuffer.get_end_iter(), True)
  412.         self.xml.outputView.scroll_to_mark(end_mark, 0)
  413.         self.xml.outputlabel.set_label("<b>Output</b>")
  414.  
  415.     def outputUnbold(self, obj, data):
  416.         self.xml.outputlabel.set_label("Output")
  417.  
  418.     def fstabUnbold(self, obj, data):
  419.         self.xml.fstablabel.set_label("Fstab")
  420.  
  421.     def showFolderChooser(self, obj):
  422.         self.xml.folderchooser.present()
  423.  
  424.     def choseMountpoint(self, obj, response):
  425.         if response == gtk.RESPONSE_OK:
  426.             model, iter = self.partSelection.get_selected()
  427.             device = model.get_value(iter, 1)
  428.             mountpoint = self.xml.folderchooser.get_filename()
  429.             self.partInfo.partitions[device].mountpoint = mountpoint
  430.             model.set_value(iter, 2, mountpoint)
  431.             print "Setting %s to mount at %s" % (device, mountpoint)
  432.         else:
  433.             pass
  434.         self.xml.folderchooser.hide()
  435.  
  436.     def saveFstab(self, obj):
  437.         for partition in self.partInfo.partitions:
  438.             device = self.partInfo.partitions[partition]
  439.             if device.mountpoint == "":
  440.                 continue
  441.             if device.fs == "unknown":
  442.                 fs = "auto"
  443.             else:
  444.                 fs = device.fs
  445.             fstabentry = "%s%s\t %s\t %s\t defaults 0 0" % (DEV, device.name, device.mountpoint, fs)
  446.             
  447.             if device.fstabIndex >= 0:
  448.                 self.partInfo.fstab[device.fstabIndex] = fstabentry
  449.             else:
  450.                 self.partInfo.fstab.append(fstabentry)
  451.                 # The fstabIndex will now be the last line in the fstab, where we just appended the line
  452.                 device.fstabIndex = len(self.partInfo.fstab) - 1 
  453.         self.updateFstabView()
  454.         return
  455.  
  456.     def quit(self, obj):
  457.         gtk.main_quit()
  458.  
  459.     
  460. driver = MountGui()
  461. gtk.main()
  462.